package activity

import (
	"context"
	"strconv"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/utils/pointy"
	enum "mall/service/backend/common/enum/promotion"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/promotion/model"
	"mall/service/promotion/rpc/internal/svc"
	"mall/service/promotion/rpc/internal/utils/errorhandler"
	"mall/service/promotion/rpc/types/promotion"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetActivityByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetActivityByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetActivityByIdLogic {
	return &BackendGetActivityByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetActivityByIdLogic) BackendGetActivityById(in *promotion.ActivityIdReq) (*promotion.ActivityInfo, error) {
	if in.Id == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	res, err := l.svcCtx.Activity.FindOne(l.ctx, in.Id)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	var meta []*promotion.MetaInfo
	if in.WithMeta != nil && *in.WithMeta > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.PromotionActivityMetumColumns.ActivityID] = map[string][]any{
			"equalTo": {in.Id},
		}
		list, _, err := l.svcCtx.Activity.GetMeta(l.ctx, model.M{}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				if v.MetaKey == "_thumbnail_id" || v.MetaKey == "_thumbnail_url" {
					continue
				}

				if len(v.MetaKey) > 0 && v.MetaValue.Valid {
					meta = append(meta, &promotion.MetaInfo{
						Id:    &v.MetaID,
						Key:   &v.MetaKey,
						Value: &v.MetaValue.String,
					})
				}
			}
		}
	}

	var media []*promotion.MediaInfo
	if in.WithMedia != nil && *in.WithMedia > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.PromotionAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {in.Id},
		}
		filterMap[model.PromotionAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.AttachmentLogTypePromotion},
		}
		var orderBy string = model.PromotionAttachmentRelationshipColumns.AttachmentThumbnail + " DESC, " +
			model.PromotionAttachmentRelationshipColumns.AttachmentOrder
		list, _, err := l.svcCtx.Activity.GetMedia(l.ctx, model.M{
			"orderBy": orderBy,
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				media = append(media, &promotion.MediaInfo{
					Uid:       &v.AttachmentRelationshipID,
					Id:        pointy.GetPointer(strconv.FormatUint(v.AttachmentID, 10)),
					Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
					Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
					Uri:       &v.AttachmentSource,
					Url:       &v.AttachmentImageURL,
					AltText:   &v.AttachmentImageAlt,
					MetaData:  &v.AttachmentImageMeta,
				})
			}
		}
	}

	var groups []*promotion.ActivityRuleGroupInfo
	if (res.ActivityType == enum.PromotionActivityDiscount || res.ActivityType == enum.PromotionActivityMember ||
		res.ActivityType == enum.PromotionActivityCharge) &&
		in.WithRules != nil && *in.WithRules > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.PromotionRuleGroupColumns.ActivityID] = map[string][]any{
			"equalTo": {in.Id},
		}
		filterMap[model.PromotionRuleGroupColumns.Status] = map[string][]any{
			"equalTo": {globalkey.StatusEnabled},
		}
		list, _, err := l.svcCtx.Activity.GetRuleGroupList(l.ctx, model.M{
			"orderBy": model.PromotionRuleGroupColumns.Sort,
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			var groupIds []any
			for _, v := range list {
				groupIds = append(groupIds, v.GroupID)
			}

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.PromotionRuleColumns.ActivityID] = map[string][]any{
				"equalTo": {in.Id},
			}
			subFilterMap[model.PromotionRuleColumns.GroupID] = map[string][]any{
				"in": groupIds,
			}
			subFilterMap[model.PromotionRuleColumns.Status] = map[string][]any{
				"equalTo": {globalkey.StatusEnabled},
			}
			rules, _, err := l.svcCtx.Activity.GetRuleList(l.ctx, model.M{
				"orderBy": model.PromotionRuleColumns.Sort,
			}, -1, subFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			groupRuleMap := make(map[uint64][]*promotion.ActivityRuleInfo)
			if len(rules) > 0 {
				for _, v := range rules {
					var regions *string
					var value string
					switch v.RuleType {
					case enum.PromotionActivityRuleTypeDiscount:
						switch v.Mode {
						case enum.PromotionActivityRuleModeAmount, enum.PromotionActivityRuleModeFixed:
							value = moneyx.FormatAmount(int64(v.Value))
						case enum.PromotionActivityRuleModeDiscount:
							value = strconv.FormatUint(v.Value, 10)
						}
					case enum.PromotionActivityRuleTypeFreeShipping:
						if v.Regions.Valid {
							regions = pointy.GetPointer(string(v.Regions.JSON))
						}
					case enum.PromotionActivityRuleTypeExtraPoint:
						value = strconv.FormatUint(v.Value, 10)
					case enum.PromotionActivityRuleTypeCoupon:
						value = strconv.FormatUint(v.Value, 10)
					}

					groupRuleMap[v.GroupID] = append(groupRuleMap[v.GroupID], &promotion.ActivityRuleInfo{
						Id:         &v.RuleID,
						ActivityId: &v.ActivityID,
						GroupId:    &v.GroupID,
						RuleType:   pointy.GetPointer(uint32(v.RuleType)),
						Regions:    regions,
						Mode:       pointy.GetPointer(uint32(v.Mode)),
						Value:      &value,
					})
				}
			}

			for _, v := range list {
				if rs, ok := groupRuleMap[v.GroupID]; ok {
					var threshold string
					switch res.GroupMode {
					case enum.PromotionActivityRuleModeAmount:
						threshold = moneyx.FormatAmount(int64(v.Threshhold))
					case enum.PromotionActivityRuleModeDiscount:
						threshold = strconv.FormatUint(v.Threshhold, 10)
					}

					groups = append(groups, &promotion.ActivityRuleGroupInfo{
						Id:         &v.GroupID,
						ActivityId: &v.ActivityID,
						Threshold:  &threshold,
						Rules:      rs,
					})
				}
			}
		}
	}

	return &promotion.ActivityInfo{
		Id:                    &res.ID,
		Name:                  &res.Name,
		Slug:                  &res.Slug,
		Desc:                  &res.Description,
		FilteredDesc:          &res.DescriptionFiltered,
		MemberRestriction:     &res.MemberRestriction,
		ActivityType:          pointy.GetPointer(uint32(res.ActivityType)),
		MutexType:             pointy.GetPointer(uint32(res.MutexType)),
		ScopeType:             pointy.GetPointer(uint32(res.ScopeType)),
		TimesLimit:            pointy.GetPointer(uint32(res.TimesLimit)),
		GroupMode:             pointy.GetPointer(uint32(res.GroupMode)),
		GroupType:             pointy.GetPointer(uint32(res.GroupType)),
		SeckillLimit:          pointy.GetPointer(uint32(res.SeckillLimit)),
		SeckillCancelDuration: pointy.GetPointer(uint32(res.SeckillCancelDuration)),
		SeckillNotifyDuration: pointy.GetPointer(uint32(res.SeckillNotifyDuration)),
		PackageType:           pointy.GetPointer(uint32(res.PackageType)),
		PackagePicId:          &res.PackagePicID,
		PackagePicUrl:         &res.PackagePicURL,
		Sort:                  pointy.GetPointer(uint32(res.Sort)),
		Status:                pointy.GetPointer(uint32(res.Status)),
		Step:                  pointy.GetPointer(uint32(res.CreateStep)),
		StartedAt:             pointy.GetPointer(modelx.FormatNullDotTime(res.StartedAt, "")),
		EndedAt:               pointy.GetPointer(modelx.FormatNullDotTime(res.EndedAt, "")),
		CreatedAt:             pointy.GetPointer(modelx.FormatTime(res.CreatedAt, "")),
		UpdatedAt:             pointy.GetPointer(modelx.FormatTime(res.UpdatedAt, "")),
		DeletedAt:             pointy.GetPointer(modelx.FormatNullDotTime(res.DeletedAt, "")),
		Groups:                groups,
		Meta:                  meta,
		Media:                 media,
	}, nil
}
